
package com.bong.panpan.bongcharttools.ble;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothProfile;
import android.content.Context;

import com.bong.panpan.bongcharttools.server.HeartRateServer;

import java.util.ArrayList;

/**
 * Created by panpan on 2017/8/21.
 */

public class HeartBleLink implements HeartRateServer.bleHrsEvt {

    public int id = 0;
    private BluetoothGatt mBluetoothGatt;
    private BluetoothGattCharacteristic txChar, rxChar;
    private String address = "", name = "";
    private HeartRateServer heartRateServer = new HeartRateServer();

    private BluetoothGattCallback bleCallBack = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

            if (status == BluetoothGatt.GATT_SUCCESS) {
                if (newState == BluetoothProfile.STATE_CONNECTING) {

                }
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    if (gatt.discoverServices()) {
                        OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISCOVERING);
                    } else {
                        errorMsg = "发现服务失败！";
                        OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKFAILED);
                        OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISLINK);
                    }
                }
                if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    if (deviceState == BleDeviceState.DEVICE_STATE_LINKING) {
                        OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKFAILED);
                        OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISLINK);
                    }
                    if (deviceState == BleDeviceState.DEVICE_STATE_DISCOVERING) {
                        OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKFAILED);
                        OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISLINK);
                    }
                    if (deviceState == BleDeviceState.DEVICE_STATE_LINKED) {
                        OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKLOST);
                        OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISLINK);
                    }
                }
            } else {
                if (deviceState == BleDeviceState.DEVICE_STATE_LINKED) {
                    OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKLOST);
                    OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISLINK);
                } else {
                    OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKFAILED);
                    OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISLINK);
                }
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (heartRateServer.bleHrsDiscEvt(gatt, status)) {
                OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKED);
            } else {
                errorMsg = "未发现心率服务";
                OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKFAILED);
                OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISLINK);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            heartRateServer.onCharacteristicRead(gatt, characteristic, status);
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            heartRateServer.onHvx(gatt, characteristic);
        }

        @Override
        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorRead(gatt, descriptor, status);
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
        }

        @Override
        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            super.onReliableWriteCompleted(gatt, status);
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
        }
    };

    public String getErrorMsg() {
        return errorMsg;
    }

    public void addBleListener(BleListener bleListener) {
        if (this.bleListener.indexOf(bleListener) == -1)
            this.bleListener.add(bleListener);
    }

    public void removeBleListener(BleListener bleListener) {
        this.bleListener.remove(bleListener);
    }

    public void clearBleListener(BleListener bleListener) {
        this.bleListener.clear();
    }

    public String getAddress() {
        return address;
    }

    public String getName() {
        return name;
    }

    private String errorMsg = "";
    private ArrayList<BleListener> bleListener = new ArrayList<>();
    private Context context;
    private BleDeviceState deviceState = BleDeviceState.DEVICE_STATE_DISLINK;

    public HeartBleLink(Context context) {
        this.context = context;
        heartRateServer.bleHrsInit(this);
    }

    public boolean link(BluetoothDevice device) {
        address = device.getAddress();
        name = device.getName();
        mBluetoothGatt = device.connectGatt(context, false, bleCallBack);
        if (mBluetoothGatt != null) {
            OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKING);
            return true;
        } else {
            OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_LINKFAILED);
            OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISLINK);
        }
        return false;
    }

    public synchronized void dislink() {
        if (deviceState != BleDeviceState.DEVICE_STATE_DISLINK) {
            if (mBluetoothGatt != null) {
                mBluetoothGatt.disconnect();
                if (mBluetoothGatt != null)
                    mBluetoothGatt.close();
                mBluetoothGatt = null;
            }
            OnDeviceStateChanged(BleDeviceState.DEVICE_STATE_DISLINK);
        }
    }

    /**
     * @return true 发送成功
     */
    public boolean sendData(byte... data) {
        if (deviceState == BleDeviceState.DEVICE_STATE_LINKED) {
            rxChar.setValue(data);
            return mBluetoothGatt.writeCharacteristic(rxChar);
        }
        return false;
    }

    void OnDeviceStateChanged(BleDeviceState state) {
        if (this.deviceState != state) {
            deviceState = state;
            if (state == BleDeviceState.DEVICE_STATE_DISLINK && mBluetoothGatt != null) {
                heartRateServer.onDisconnected(mBluetoothGatt);
                mBluetoothGatt.close();
                mBluetoothGatt = null;
            }
            for (BleListener listener : bleListener) {
                listener.OnDeviceStateChanged(this, state);
            }

        }
    }

    void OnDataReceived(int hr_value, int rr_intervals[], int rr_intervals_cnt) {
        for (BleListener listener : bleListener) {
            listener.OnDataReceived(this, hr_value, rr_intervals, rr_intervals_cnt);
        }
    }

    @Override
    public void evtHandler(int hr_value, int[] rr_intervals, int rr_intervals_cnt) {
        OnDataReceived(hr_value, rr_intervals, rr_intervals_cnt);
    }

    public interface BleListener {
        void OnDeviceStateChanged(HeartBleLink bleLink, BleDeviceState state);

        void OnDataReceived(HeartBleLink bleLink, int hr_value, int rr_intervals[], int rr_intervals_cnt);
    }

    public BleDeviceState getDeviceState() {
        return deviceState;
    }

    public HeartRateServer getHeartRateServer() {
        return heartRateServer;
    }
}
